package com.gitee.qdbp.general.system.api.permission.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import com.gitee.qdbp.base.system.model.ICascadeResource;

/**
 * 权限资源层级关系
 *
 * @author zhaohuihua
 * @version 170505
 */
public class ResourceCascadeBean extends ResourceCoreBean implements ICascadeResource<ResourceCascadeBean> {

    /** 版本序列号 **/
    private static final long serialVersionUID = 1L;

    /** 子权限列表 **/
    private List<ResourceCascadeBean> children;

    /** 第一个子权限 **/
    public ResourceCascadeBean getFirst() {
        if (children == null || children.isEmpty()) {
            return null;
        } else {
            return this.children.get(0);
        }
    }

    /** 子权限列表 **/
    public List<ResourceCascadeBean> getChildren() {
        return children;
    }

    /** 子权限列表 **/
    public void setChildren(List<ResourceCascadeBean> children) {
        this.children = children;
    }

    /** 增加子权限 **/
    public void addChild(ResourceCascadeBean child) {
        if (children == null) {
            children = new ArrayList<>();
        }
        children.add(child);
    }

    /** 广度优先遍历, 当前节点自身不会参与遍历 **/
    public Iterator<ResourceCascadeBean> breadthFirstIterator() {
        return new BreadthFirstIterator(this);
    }

    /** 深度度优先遍历, 当前节点自身不会参与遍历 **/
    public Iterator<ResourceCascadeBean> depthFirstIterator() {
        return new DepthFirstIterator(this);
    }

    private static class Item {

        private ResourceCascadeBean parent;
        private ResourceCascadeBean self;

        public Item(ResourceCascadeBean parent, ResourceCascadeBean self) {
            this.parent = parent;
            this.self = self;
        }
    }

    /**
     * 广度优先遍历<br>
     * 根节点自身不会参与遍历
     *
     * @author zhaohuihua
     * @version 170507
     */
    private static class BreadthFirstIterator implements Iterator<ResourceCascadeBean> {

        private Queue<Item> queue;

        private Item last;

        public BreadthFirstIterator(ResourceCascadeBean root) {
            queue = new LinkedList<>();
            if (root.getChildren() != null && !root.getChildren().isEmpty()) {
                for (ResourceCascadeBean child : root.getChildren()) {
                    queue.offer(new Item(root, child));
                }
            }
        }

        public boolean hasNext() {
            return !queue.isEmpty();
        }

        public ResourceCascadeBean next() {
            Item next = queue.poll();
            if (next.self.getChildren() != null) {
                for (ResourceCascadeBean i : next.self.getChildren()) {
                    queue.offer(new Item(next.self, i));
                }
            }
            last = next;
            return next.self;
        }

        public void remove() {
            if (last == null) {
                throw new IllegalStateException("Call remove() must be after the next().");
            }

            // 先将当前节点从父节点的children中删除
            last.parent.getChildren().remove(last.self);
            if (last.parent.getChildren().isEmpty()) {
                last.parent.setChildren(null);
            }
            if (last.self.getChildren() != null && !last.self.getChildren().isEmpty()) {
                // 再把当前节点的子节点从队列中删除
                // 因为当前节点的子节点在调用next()时已经加到遍历队列中了(孙子节点还没有加到队列中)
                Iterator<Item> itr = queue.iterator();
                while (itr.hasNext()) {
                    Item next = itr.next();
                    if (last.self.getId().equals(next.self.getParentId())) {
                        itr.remove();
                    }
                }
            }
            last = null;
        }
    }

    /**
     * 深度优先遍历<br>
     * 根节点自身不会参与遍历
     *
     * @author zhaohuihua
     * @version 170801
     */
    private static class DepthFirstIterator implements Iterator<ResourceCascadeBean> {

        private Queue<Item> queue;

        private Item last;

        public DepthFirstIterator(ResourceCascadeBean root) {
            queue = new LinkedList<>();
            if (root.getChildren() != null && !root.getChildren().isEmpty()) {
                for (ResourceCascadeBean child : root.getChildren()) {
                    recursiveOffer(root, child);
                }
            }
        }

        private void recursiveOffer(ResourceCascadeBean parent, ResourceCascadeBean self) {
            queue.offer(new Item(parent, self));
            if (self.getChildren() != null && !self.getChildren().isEmpty()) {
                for (ResourceCascadeBean child : self.getChildren()) {
                    recursiveOffer(self, child);
                }
            }
        }

        public boolean hasNext() {
            return !queue.isEmpty();
        }

        public ResourceCascadeBean next() {
            Item next = queue.poll();
            last = next;
            return next.self;
        }

        public void remove() {
            if (last == null) {
                throw new IllegalStateException("Call remove() must be after the next().");
            }

            // 先将当前节点从父节点的children中删除
            last.parent.getChildren().remove(last.self);
            if (last.parent.getChildren().isEmpty()) {
                last.parent.setChildren(null);
            }
            if (last.self.getChildren() != null && !last.self.getChildren().isEmpty()) {
                // 收集所有后代节点的ID
                Map<String, Boolean> map = new HashMap<>();
                collectAllChildrenId(map, last.self);

                // 把所有后代节点从队列中删除
                Iterator<Item> itr = queue.iterator();
                while (itr.hasNext()) {
                    Item next = itr.next();
                    if (map.containsKey(next.self.getId())) {
                        itr.remove();
                    }
                }
            }
            last = null;
        }

        // 收集所有后代节点的ID
        private void collectAllChildrenId(Map<String, Boolean> map, ResourceCascadeBean self) {
            if (self.getChildren() != null) {
                for (ResourceCascadeBean child : self.getChildren()) {
                    map.put(child.getId(), true);
                    collectAllChildrenId(map, child);
                }
            }
        }
    }

}
